package plus;

import plus.run.Emit;

/**
 * Represents a home for variable storage
 * @author me
 *
 */
public class DynamicExtent {
	// I'm considering module-level vars (and program globals) to be in the "loader".
	// That's admittedly a bit odd, considering. And to avoid repetition of code,
	// it might actually make more sense to completely decouple the "subroutine" from
	// the "Dynamic Scope" object, and just manage those separately.
	// So that will be the way of it.
	
	public static DynamicExtent cur;
	/**
	 * In the current design, no attempt is made to combine slots based on
	 * value lifespan. A very simple implementation is sufficient.
	 * 
	 * Activation Record Picture:
	 *   Return Value
	 *   Param k       -------------+
	 *   Param k-1                  |
	 *   ...         To be cleaned: | k+1 words
	 *   Param 1                    |
	 *   Static Link   -------------+
	 *   Return address
	 *   Dynamic Link  <-- BP points here
	 *   Local 1
	 *   Local 2..N
	 *   Temp working space
	 * 
	 * @author me
	 *
	 */
	
	public final int lexLevel;
	public DynamicExtent(int depth) {
		lexLevel = depth;
	}
	int pLocal = 0; private int nextLocal() { return --pLocal; }
	public int pParam = 3; // Next param at [bp] + 3 words as detailed above.
	public Type range; // It turns out we need this for return-statements to type out correctly.
	int nextParam() { return pParam++; } // room) for the old BP and the return address.
	Variable newParam(Type type) {
		Variable v = new Variable(lexLevel, nextParam(), type);
		v.assigned = true;
		return v;
	}
	
	Variable newLocal() { return new Variable(lexLevel, nextLocal()); }
	Variable newLocal(Type type) { return new Variable(lexLevel, nextLocal(), type); }
	/**
	 * @return 1 or more when inside a subroutine; 0 for global scope.
	 * Thus, global-scoped functions should be given BSS for a static scope.
	 * In principle, then, they don't require a static pointer when called
	 * because it's implied by the environment, linker, etc. But since that
	 * multiplies calling conventions, I'll just supply one. 
	 */
	
	public void compileEnter() {
		cur = this;
		Emit.enter(-pLocal); // number of words for local variables.
	}
	
	public void compileExit() {
		Emit.exit(pParam - 2); // actual number of words to drop after RTS.
		cur = null;
	}
	public void setRange(Type type) { range = type; }
	
}
